package install

import (
	"io"
	"os"
	"path"
	"strconv"
	"time"

	"gitee.com/shaddy/k3sinstall/mylog"
	"github.com/pkg/sftp"
	"golang.org/x/crypto/ssh"
)

type K3sConfig struct {
	Masters       []string
	Nodes         []string
	MHostName     []string
	NHoseName     []string
	MasterNameTag string
	NodeNameTag   string
	User          string
	Passwd        string
	ConfigFile    string
	WorkDir       string
	PkgFile       string
	ImgFile       string
}

func (c *K3sConfig) transFile(filename string) {
	_, pkgfilename := path.Split(filename)
	c.PkgFile = pkgfilename
	allNode := append(c.Masters, c.Nodes...)
	for hostIp := range allNode {
		tmpClient, err := ssh.Dial("tcp", allNode[hostIp], &ssh.ClientConfig{
			User: c.User,
			Auth: []ssh.AuthMethod{
				ssh.Password(c.Passwd),
			},
			HostKeyCallback: ssh.InsecureIgnoreHostKey(),
			ClientVersion:   "",
			Timeout:         10 * time.Second,
		})
		if err != nil {
			mylog.Error.Printf("连接服务器失败 %s : %s\n", allNode[hostIp], err)
		}
		defer tmpClient.Close()
		sftpTmpClient, err := sftp.NewClient(tmpClient)
		if err != nil {
			mylog.Error.Panicf("连接服务器时，创建sftp session 失败 %s : %s", allNode[hostIp], err)
		}
		defer sftpTmpClient.Close()
		remoteFile, err := sftpTmpClient.Create(sftp.Join(c.WorkDir, c.PkgFile))
		if err != nil {
			mylog.Error.Panicf("连接服务器时，创建文件失败 %s : %s", allNode[hostIp], err)
		}
		defer remoteFile.Close()
		localFile, err := os.Open(filename)
		if err != nil {
			mylog.Error.Panicf("上传文件时，打开本地文件失败 %s : %s", allNode[hostIp], err)
		}
		defer localFile.Close()
		_, err = io.Copy(remoteFile, localFile)
		if err != nil {
			mylog.Error.Panicf("上传文件失败 %s : %s", allNode[hostIp], err)
		}

	}
}

func (c *K3sConfig) synTransFileForOneNode(host string) {

	tmpClient, err := ssh.Dial("tcp", host, &ssh.ClientConfig{
		User: c.User,
		Auth: []ssh.AuthMethod{
			ssh.Password(c.Passwd),
		},
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
		ClientVersion:   "",
		Timeout:         10 * time.Second,
	})
	if err != nil {
		mylog.Error.Printf("连接服务器失败 %s : %s\n", host, err)
	}
	defer tmpClient.Close()
	sftpTmpClient, err := sftp.NewClient(tmpClient)
	if err != nil {
		mylog.Error.Panicf("连接服务器时，创建sftp session 失败 %s : %s", host, err)
	}
	defer sftpTmpClient.Close()
	remoteFile, err := sftpTmpClient.Create(sftp.Join(c.WorkDir, c.PkgFile))
	if err != nil {
		mylog.Error.Panicf("连接服务器时，创建文件失败 %s : %s", host, err)
	}
	defer remoteFile.Close()
	localFile, err := os.Open(c.PkgFile)
	if err != nil {
		mylog.Error.Panicf("上传文件时，打开本地文件失败 %s : %s", host, err)
	}
	defer localFile.Close()
	_, err = io.Copy(remoteFile, localFile)
	if err != nil {
		mylog.Error.Panicf("上传文件失败 %s : %s", host, err)
	}

}

func (c *K3sConfig) runCmdMasterAndNode(cmd string) {
	allNode := append(c.Masters, c.Nodes...)
	c.runCmd(allNode, cmd)

}

func (c *K3sConfig) runCmdForAllMasters(cmd string) {
	c.runCmd(c.Masters, cmd)
}

func (c *K3sConfig) runCmdForMaster0(cmd string) {
	c.runCmd([]string{c.Masters[0]}, cmd)
}

func (c *K3sConfig) runCmdForAllNodes(cmd string) {
	c.runCmd(c.Nodes, cmd)
}

func (c *K3sConfig) runCmd(allNode []string, cmd string) {

	for hostIp := range allNode {
		tmpClient, err := ssh.Dial("tcp", allNode[hostIp], &ssh.ClientConfig{
			User: c.User,
			Auth: []ssh.AuthMethod{
				ssh.Password(c.Passwd),
			},
			HostKeyCallback: ssh.InsecureIgnoreHostKey(),
			ClientVersion:   "",
			Timeout:         10 * time.Second,
		})
		if err != nil {
			mylog.Error.Printf("连接服务器失败 %s : %s\n", allNode[hostIp], err)
		}
		defer tmpClient.Close()
		tmpSession, err := tmpClient.NewSession()
		if err != nil {
			mylog.Error.Printf("连接服务器时，创建session 失败 %s : %s", allNode[hostIp], err)
		}
		defer tmpSession.Close()
		echostr, err := tmpSession.CombinedOutput(cmd)
		if err != nil {
			mylog.Error.Printf("连接服务器时，执行命令失败 %s %s: %s", allNode[hostIp], cmd, err)
		}
		mylog.Info.Printf("执行命令成功： %s 执行命令: %s 结果返回是: %s", allNode[hostIp], cmd, string(echostr))
	}

}

func synRunCmd(host string, user string, passwd string, cmd string) string {

	tmpClient, err := ssh.Dial("tcp", host, &ssh.ClientConfig{
		User: user,
		Auth: []ssh.AuthMethod{
			ssh.Password(passwd),
		},
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
		ClientVersion:   "",
		Timeout:         10 * time.Second,
	})
	if err != nil {
		mylog.Error.Printf("连接服务器失败 %s : %s\n", host, err)
	}
	defer tmpClient.Close()
	tmpSession, err := tmpClient.NewSession()
	if err != nil {
		mylog.Error.Printf("连接服务器时，创建session 失败 %s : %s", host, err)
	}
	defer tmpSession.Close()
	echostr, err := tmpSession.CombinedOutput(cmd)
	if err != nil {
		mylog.Error.Printf("连接服务器时，执行命令失败 %s : %s", host, err)
	}
	return string(echostr)
}

func (c *K3sConfig) setHostName() {

	for hostIp := range c.Masters {
		tmpClient, err := ssh.Dial("tcp", c.Masters[hostIp], &ssh.ClientConfig{
			User: c.User,
			Auth: []ssh.AuthMethod{
				ssh.Password(c.Passwd),
			},
			HostKeyCallback: ssh.InsecureIgnoreHostKey(),
			ClientVersion:   "",
			Timeout:         10 * time.Second,
		})
		if err != nil {
			mylog.Error.Printf("连接服务器失败 %s : %s\n", c.Masters[hostIp], err)
		}
		defer tmpClient.Close()
		tmpSession, err := tmpClient.NewSession()
		if err != nil {
			mylog.Error.Printf("连接服务器时，创建session 失败 %s : %s", c.Masters[hostIp], err)
		}
		defer tmpSession.Close()
		echostr, err := tmpSession.CombinedOutput("hostnamectl set-hostname " + c.MasterNameTag + strconv.Itoa(hostIp))
		if err != nil {
			mylog.Error.Printf("连接服务器时，执行命令失败 %s : %s", c.Masters[hostIp], err)
		}
		c.MHostName = append(c.MHostName, c.MasterNameTag+strconv.Itoa(hostIp))
		mylog.Info.Printf("执行命令成功： %s 结果返回是: %s", c.Masters[hostIp], string(echostr))
	}

	for hostIp := range c.Nodes {
		tmpClient, err := ssh.Dial("tcp", c.Nodes[hostIp], &ssh.ClientConfig{
			User: c.User,
			Auth: []ssh.AuthMethod{
				ssh.Password(c.Passwd),
			},
			HostKeyCallback: ssh.InsecureIgnoreHostKey(),
			ClientVersion:   "",
			Timeout:         10 * time.Second,
		})
		if err != nil {
			mylog.Error.Printf("连接服务器失败 %s : %s\n", c.Nodes[hostIp], err)
		}
		defer tmpClient.Close()
		tmpSession, err := tmpClient.NewSession()
		if err != nil {
			mylog.Error.Printf("连接服务器时，创建session 失败 %s : %s", c.Nodes[hostIp], err)
		}
		defer tmpSession.Close()
		echostr, err := tmpSession.CombinedOutput("hostnamectl set-hostname " + c.NodeNameTag + strconv.Itoa(hostIp))
		if err != nil {
			mylog.Error.Printf("连接服务器时，执行命令失败 %s : %s", c.Masters[hostIp], err)
		}
		c.NHoseName = append(c.NHoseName, c.NodeNameTag+strconv.Itoa(hostIp))
		mylog.Info.Printf("执行命令成功： %s 结果返回是: %s", c.Nodes[hostIp], string(echostr))
	}

}
